/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010.

	This file is part of Maxsi Installer.

	Maxsi Installer is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi Installer is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
	License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Installer. If not, see <http://www.gnu.org/licenses/>.

	MaxsiInstaller.exe
	The UI front-end for the Maxsi Distribution library.

	Main.cpp
	Handles the creation of the UI and the program mainloop.

******************************************************************************/

#include "MaxsiEngine.h"
#include "Main.h"

MESTR*	ProductName		=	NULL;
MESTR*	MasterServer	=	NULL;

MaxsiInstaller::MaxsiInstaller()
{
	Header				=	NULL;
	SeparatorTop		=	NULL;
	SeparatorBottom		=	NULL;
	ProgressBar			=	NULL;
	StatusLabel			=	NULL;
	SubStatusLabel		=	NULL;
	cmdRetry			=	NULL;
	ProductNameField	=	NULL;
	MasterServerField	=	NULL;
	ProductNameLabel	=	NULL;
	MasterServerLabel	=	NULL;

	WindowTitle			=	BuildString(1, Translate("MaxsiInstaller/DefaultWindowTitle"));
}

MaxsiInstaller::~MaxsiInstaller()
{
	IFDEL(WindowTitle);	
}

bool MaxsiInstaller::CreateControls()
{
	if ( ControlSystem() == NULL ) { return false; }

	SeparatorTop		=	ControlSystem()->CreateSeparatorH(Window);
	SeparatorBottom		=	ControlSystem()->CreateSeparatorH(Window);

	cmdRetry			=	new MaxsiWindowButton(this, WindowSystem(), ControlSystem());
	if ( cmdRetry == NULL || cmdRetry->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	Header				=	new MaxsiWindowLabel(this, WindowSystem(), ControlSystem());
	if ( Header == NULL || Header->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	StatusLabel			=	new MaxsiWindowLabel(this, WindowSystem(), ControlSystem());
	if ( StatusLabel == NULL || StatusLabel->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	SubStatusLabel		=	new MaxsiWindowLabel(this, WindowSystem(), ControlSystem());
	if ( SubStatusLabel == NULL || SubStatusLabel->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	ProductNameLabel	=	new MaxsiWindowLabel(this, WindowSystem(), ControlSystem());
	if ( ProductNameLabel == NULL || ProductNameLabel->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	MasterServerLabel	=	new MaxsiWindowLabel(this, WindowSystem(), ControlSystem());
	if ( MasterServerLabel == NULL || MasterServerLabel->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	ProductNameField	=	new MaxsiWindowTextSingleLine(this, WindowSystem(), ControlSystem());
	if ( ProductNameField == NULL || ProductNameField->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	MasterServerField	=	new MaxsiWindowTextSingleLine(this, WindowSystem(), ControlSystem());
	if ( MasterServerField == NULL || MasterServerField->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	ProgressBar			=	new MaxsiWindowProgressBar(this, WindowSystem(), ControlSystem());
	if ( ProgressBar == NULL || ProgressBar->Initialize() != MAXSI_ERROR_SUCCESS ) { return false; }

	MESTR* cmdRetryText = Translate("MaxsiInstaller/ButtonInstall");

	if ( cmdRetry && cmdRetryText ) { cmdRetry->SetText(cmdRetryText); }

	if ( ProductName && MasterServer )
	{
		//Connect();
	}
	else
	{
		Init_RequestParameters();
		//Init_Connecting();
	}

	return true;
}

bool MaxsiInstaller::DeleteControls()
{
	IFDELSINGLE(Header);
	IFDELSINGLE(StatusLabel);
	IFDELSINGLE(SubStatusLabel);
	IFDELSINGLE(ProductNameLabel);
	IFDELSINGLE(MasterServerLabel);
	IFDELSINGLE(cmdRetry);
	IFDELSINGLE(ProductNameField);
	IFDELSINGLE(MasterServerField);
	IFDELSINGLE(ProgressBar);

	return true;
}

bool MaxsiInstaller::UpdateControls()
{
	MoveWindow(SeparatorTop, 25, 50, Width-2*25, 3, true);
	MoveWindow(SeparatorBottom, 25, Height-2.5*24, Width-2*25, 3, true);

	Header->Move(25, 30, Width-25-25, 20);

	StatusLabel->Move(25, 60, Width-25-25, 30);

	ProgressBar->Move(25, StatusLabel->Bottom(), Width-25-25, 18);

	SubStatusLabel->Move(25, ProgressBar->Bottom(), Width-25-25, Height-115-3*24);

	ProductNameLabel->Move(25, StatusLabel->Bottom()+10, Width-25-25, 24);
	ProductNameField->Move(25, ProductNameLabel->Bottom(), Width-25-25, 24);

	MasterServerLabel->Move(25, ProductNameField->Bottom()+10, Width-25-25, 20);
	MasterServerField->Move(25, MasterServerLabel->Bottom(), Width-25-25, 24);

	cmdRetry->Move(Width-1*125, Height-2*24, 100, 24);

	return true;
}

MESTR* MaxsiInstaller::GetWindowTitle()
{
	return BuildString(1, WindowTitle);
}

int MaxsiInstaller::GetDefaultWidth()
{
	return 500;
}

int MaxsiInstaller::GetDefaultHeight()
{
	return 370;
}

bool MaxsiInstaller::UpdateWindowIcon()
{
	MaxsiHandle		Icon	=	WindowSystem()->CreatePictureBufferFromFile(_MESTR("../Images/MaxsiInstallerIcon.ico"));

	if (!Icon) { return false; }

	return WindowSystem()->SetWindowIcon(Window, Icon);
}

bool MaxsiInstaller::Init_RequestParameters()
{
	Init_NeedInput	=	true;

	Header->SetFont(WindowSystem()->GetDefaultBoldFont());
	Header->SetText(Translate("MaxsiInstaller/WelcomeToInstaller"));

	StatusLabel->SetText(Translate("MaxsiInstaller/AdvancedInstallInstructions"));
	ProductNameLabel->SetText(Translate("MaxsiInstaller/AdvancedInstallProductNameLabel"));
	MasterServerLabel->SetText(Translate("MaxsiInstaller/AdvancedInstallMasterContentServerLabel"));

	ProgressBar->Hide();
	ProductNameField->Show();
	MasterServerField->Show();
	ProductNameLabel->Show();
	MasterServerLabel->Show();
	StatusLabel->Show();
	SubStatusLabel->Hide();

	return true;
}

bool MaxsiInstaller::Init_Connecting()
{
	Init_NeedInput	=	false;

	Header->SetFont(WindowSystem()->GetDefaultBoldFont());
	Header->SetText(Translate("MaxsiInstaller/WelcomeToInstaller"));

	StatusLabel->SetText(Translate("MaxsiInstaller/ConnectingToMasterServerToGetInitialData"));
	SubStatusLabel->SetText(_MESTR(""));

	ProgressBar->Show();
	ProgressBar->SetProgress(1.0f, MAXSI_PROGRESS_INDETERMINATE);
	ProductNameField->Hide();
	MasterServerField->Hide();
	ProductNameLabel->Hide();
	MasterServerLabel->Hide();
	StatusLabel->Show();
	SubStatusLabel->Show();

	return true;
}

#if 0

size_t HTTPCallback(void* UserData, BYTE* Data, size_t DataSize)
{	
	char Output[2] = "1";

	for ( size_t I = 0; I < DataSize; I++)
	{
		Output[0]	=	Data[I];

		printf("%s", (char*)Output);

		fflush(stdout);

		if ( Output[0] == '	' ) { usleep(8*2500); } else { usleep(2500); }
	}

	return 0;
}

class TestPeer
{
public:
	size_t Id;

	MaxsiError DoYourThing(size_t ThreadID);
};

TestPeer Testees[2];
size_t ThreadTicks[8];
bool Cake = false;

MaxsiError DoTheThings(size_t ThreadId, BYTE* Parameter)
{
	return ((TestPeer*)Parameter)->DoYourThing(ThreadId);
}

MaxsiError TestPeer::DoYourThing(size_t ThreadId)
{
	//printf("%zu", ThreadId);

	if (Cake) { return MAXSI_ERROR_SUCCESS; }

	ThreadTicks[ThreadId]++;

	/*for ( size_t I = 0; I < 256; I++) { */ScheduleWorkerThreadJob(DoTheThings, (BYTE*)&(Testees[(Id + 1) % 2])); /*}*/

	return MAXSI_ERROR_SUCCESS;
}

MaxsiError PrintMyLine(size_t ThreadId, BYTE* Parameter)
{
	char*	MyLine	=	(char*)Parameter;

	for (size_t I = 0; I < 100000; I++ )
	{
		delete[]	CalculateSHA1((BYTE*)MyLine	, strlen(MyLine));
	}

	PrintOutput("Thread: %zu: %s\n", ThreadId, MyLine);

	delete[] MyLine;

	return MAXSI_ERROR_SUCCESS;
}

int CreateWorkerThreadJobs()
{
	for ( size_t I = 0; I < 8; I++ )
	{
		MESTR* IMESTR		=	IToA64(I);
		char* Istr			=	MESTR2CHAR(IMESTR);
		char* MyLine		=	BuildStringA(3, "Hello! I am job ", Istr, "!");

		if ( MyLine == NULL ) { PrintOutput("Error allocation MyLine for %zu\n", I); }

		ScheduleWorkerThreadJob(PrintMyLine, (BYTE*)MyLine);

		delete[] IMESTR;
		delete[] Istr;
	}

	PrintOutput("Created all the jobs!\n");

	return 0;
}

int TestWorkerThreadsBigJobs()
{
	if ( CreateWorkerThreadPool() != MAXSI_ERROR_SUCCESS ) { PrintOutput("Something went wrong in CreateWorkerThreadPool()!\n"); }

	while ( true )
	{
		CreateWorkerThreadJobs();
		sleep(5);
	}

	return 0;
}

int TestWorkerThreadsPerformance()
{
	PrintOutput("Benchmarking worker threads...\n");
	
	if ( CreateWorkerThreadPool() != MAXSI_ERROR_SUCCESS ) { PrintOutput("Something went wrong in CreateWorkerThreadPool()!\n"); }

	Cake = false;

	for ( size_t I = 0; I < 8; I++ ) { ThreadTicks[I] = 0; }

	Testees[0].Id = 0;
	Testees[1].Id = 1;

	for ( size_t I = 0; I < 8; I++ ) { ScheduleWorkerThreadJob(DoTheThings, (BYTE*)&(Testees[0])); }

	size_t TimeLapsed = 5;

	sleep(TimeLapsed);

	Cake = true;
	
	sleep(1);

	PrintOutput("\nStatistics:\n");

	size_t Sum = 0;

	for ( size_t I = 0; I < 8; I++ ) { ThreadTicks[I] /= TimeLapsed; Sum += ThreadTicks[I]; }

	size_t Avg = Sum / 8;

	for ( size_t I = 0; I < 8; I++ )
	{
		printf("Thread %zu: %zu of %zu (avg=%zu) (%.1f%%)\n", I, ThreadTicks[I], Sum, Avg, (float)(ThreadTicks[I])/(float)(Avg)*100.f);
	}

	return 0;
}

int TestTestPrintString()
{
	MESTR* Sortie = _MESTR("Sorti€ḑ·gh");

	size_t Huge = 64*1000*1000*1000L;

	char* Test = TestPrintStringA("Hello! I am %s and I would like to %u, but only if %u is 10, and %z is 17, and 0x%64X isn't 12323423!\n", Sortie, 0, 10, Huge, (uint64_t)2152152521555522525);

	printf("%s", Test);

	delete[] Test;

	return 0;
}


#if 0
#if 0
	if ( argc > 1 ) { RetrieveHTTP(_MESTR("www.maxsi.dk"), _MESTR("/"), HTTPCallback); return 0; }
#else

	#define TEST_PORT 25354
	
	if ( argc == 2 )
	{
		for ( size_t I = 0; I < 3; I++ )
		{
			Async()->AsyncConnect(_MESTR("212.242.57.108"), TEST_PORT);
			//Async()->AsyncConnect(_MESTR("192.168.2.6"), TEST_PORT);
		}
	}
	else if ( argc == 3 )
	{
		Async()->AsyncListen(TEST_PORT);
	}
	//Async()->AsyncOpenFile(_MESTR("/home/sortie/Downloads/How.I.Met.Your.Mother.S05E24.720p.HDTV.X264-DIMENSION.mkv"), MAXSI_FILE_READ);

	Async()->MainLoop();

#endif
#endif

#if 0

	MaxsiHandle	Socket	=	Networking()->SyncConnectToHost(_MESTR("www.maxsi.dk"), 80);

	if ( Socket )
	{
		char* Message = "GET / HTTP/1.1\r\nhost: www.maxsi.dk\r\n\r\n";
		Networking()->SyncWriteSocket(Socket, (BYTE*)Message, strlen(Message));

		size_t Read = 1;
		char Answer[2];
	
		while ( Read != 0 )
		{
			Read = Networking()->SyncReadSocket(Socket, (BYTE*)&Answer, 1);

			Answer[1] = 0;

			printf("%s", Answer);

			fflush(stdout);

			if ( Answer[0] == '	' ) { usleep(8*2500); } else { usleep(2500); }
		}
	
		printf("\n\n");	

		Networking()->SyncCloseSocket(Socket);
	}
	else
	{
		printf("%s", "Connection failed!\n\n");
	}
#endif


#endif

int main(int argc, char** argv)
{
	//TestTestPrintString();
	//TestWorkerThreadsPerformance();

	MaxsiError	ConfigurationResult		=	LoadMaxsiComponentConfiguration(_MESTR("MaxsiInstaller"));

	MESTR* cmdRetryText = Translate("MaxsiEngine/MaxsiTranslateErrorLoadingConfiguration");	

	wprintf(cmdRetryText);
	
	MaxsiWindowSystem*	WindowSystem	=	CreateLocalWindowSystem();

	if ( WindowSystem )
	{
		if ( WindowSystem->Initialize(&argc, &argv) )
		{
			if ( ConfigurationResult != MAXSI_ERROR_SUCCESS )
			{		
				WindowSystem->MsgBox(NULL, 0, Translate("MaxsiEngine/MaxsiTranslateErrorLoadingConfiguration"), Translate("MaxsiEngine/MaxsiTranslateErrorHeader"));		
			}

			MaxsiWindow*	Window		=	new MaxsiInstaller;

			if ( Window )
			{
				Window->SetWindowSystem(WindowSystem);

				if ( Window->CreateWindow() )
				{			
					WindowSystem->MainLoop();
				}
				else
				{					
					WindowSystem->MsgBox(NULL, 0, Translate("MaxsiEngine/ErrorCreatingMainWindow"), Translate("MaxsiInstaller/DefaultWindowTitle"));			
				}
			}
			else
			{
				WindowSystem->MsgBox(NULL, 0, Translate("MaxsiEngine/ErrorAllocatingWindow"), Translate("MaxsiInstaller/DefaultWindowTitle"));				
			}

			delete Window;
		}
		else
		{
			CriticalMsgBox(NULL, 0, Translate("MaxsiEngine/ErrorInitializingWindowSystem"), Translate("MaxsiInstaller/DefaultWindowTitle"));
		}

		delete WindowSystem;
	}
	else
	{
		CriticalMsgBox(NULL, 0, Translate("MaxsiEngine/ErrorAllocatingWindowSystem"), Translate("MaxsiInstaller/DefaultWindowTitle"));
	}

	UnloadMaxsiComponentsConfigurations();

	return 0;
}

